Project Introduction

On January 12, 2010, a magnitude 7.0 earthquake struck Haiti causing significant damage which affected approximately 3 million citizens. In the wake of the disaster, aid groups were working to locate displaced persons and provide them with food and water. However, due to the large scale destruction of infrastructure over a wide area additional assistance was needed to locate people quickly.

Little is left of a neighborhood on a hillside near downtown Port-au-Prince on Jan. 15. More than a million people were displaced by the quake. (David Gilkey/NPR)

Displaced persons were known to be making make-shift shelters out of blue tarps. High resolution geo-refereneced images were captured by aircraft of the destroyed areas. The data generated by the image collection was too large for aid workers to process in time to supply aid. Therefore, a team from the Rochester Institute of Technology used data-mining algorithms to analyze the images and identify blue tarps. The goal was to effectively locate displaced persons and communicate their location to rescue workers so they could get resources to people who needed it in time.

Sample image of a geo-referenced image used for the analysis

As the final project for SYS 6018 - Data Mining, we were assigned to build models from the different techniques we learned in the course to, as accurately as possible, and in as timely a manner as possible, locate as many of the displaced persons identified in the imagery data so that they could be provided food and water before their situations became unsurvivable. The data made available to students consisted of a csv of red, green, blue pixel values and a class indicator which indicated if a pixel was representative of a blue tarp or something else like vegetation. A final hold-out data set presented in the format of multiple text files was provided as well.

Project Budget

The US Government spent $1.5B on Haiti disaster relief by the end of 2010. For this project, we will assume that 5 million dollars were allocated to our team to deliver supplies to displaced individuals in the immediate aftermath. Our team has been assigned an area where 8,000 displaced people are expected to be. Anything less than a 85% delivery success rate will be considered a disaster relief failure. 85% of 8,000 people is 6,800.

Budget $5,000,000
Cost per Delivery (True Positive)
Cost per Mis-Delivery (False Positive)
  • method of delivery
  • cost of resources
  • time from disaster to unsurvivable conditions

Analysis Methods

EDA

The data provided for analysis was generated from overhead images and stored as a three channel output. Each pixel also had a classifier label indicating whether it was a blue tarp or something else like vegetation or soil. The channels represented the red, green, and blue values for pixels within images. RGB color model is referred to as an additive model. The integer value for the red, green, and blue channels are combined to represent a color. Typically, the component values are stored as an 8 bit integer ranging from 0 to 255.

Check NA

df <- tibble(read.csv("HaitiPixels.csv")) #read in df
"Check for NA values" 
anyNA(df) #check for NA values 
"Summary of Data"
summary(df) #quick look at data
df$Class <- factor(df$Class) #make Class a factor variable. 
#> [1] "Check for NA values"
#> [1] FALSE
#> [1] "Summary of Data"
#>     Class                Red          Green            Blue      
#>  Length:63241       Min.   : 48   Min.   : 48.0   Min.   : 44.0  
#>  Class :character   1st Qu.: 80   1st Qu.: 78.0   1st Qu.: 63.0  
#>  Mode  :character   Median :163   Median :148.0   Median :123.0  
#>                     Mean   :163   Mean   :153.7   Mean   :125.1  
#>                     3rd Qu.:255   3rd Qu.:226.0   3rd Qu.:181.0  
#>                     Max.   :255   Max.   :255.0   Max.   :255.0

Scatter and Correlation

#Reference [1]
# The palette with grey:
cbPalette <- c("#999999", "#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7")
# To use for fills, add
#scale_fill_manual(values=cbPalette)
  
ggpairs(df[,2:4], lower.panel = NULL, upper = list(continuous = wrap("cor", size = 3)), aes(color=df$Class))# + scale_fill_manual(values=cbPalette) 

#view scatter and correlations
attach(df) #attach df variables 

3D Scatter

fig <- plot_ly(df, x=~Red, y=~Green, z=~Blue, color=~Class) #Reference: https://plotly.com/r/3d-scatter-plots/ https://plotly.com/r/3d-surface-plots/
fig <- fig %>% add_markers()
fig <- fig %>% layout(scene=list(xaxis=list(title="Red"),
                     yaxis = list(title = 'Green'),
                     zaxis = list(title = 'Blue')))

fig

!!!!!!!!!! IF I HAVE TIME MAKE A SELECTOR TO CHOOSE COLOR SCHEME FOR NOT COLOR BLIND OR DIFFERENT KINDS OF COLOR BLIND https://socviz.co/refineplots.html

Initial inspection of the data frame indicated no missing values. The data provided is sufficiently cleaned only one further adjustment to the data frame is needed. Since our main interest is to predict whether a pixel represents a blue tarp or not a blue tarp, the Class column of the data frame needs to be converted into a binary indicator for blue tarp or not blue tarp. This is done in the next section.

The data was visualized with the ggpairs function. For a pair of variables chosen from the data frame, Ggpairs generates a scatterplot, displays a Pearson correlation, and, on the diagonal, shows a variable distribution. The plots were also color-coded by class. The class label describes what kind of object a pixel is associated with. In our data frame there were the following classes: Blue Tarp, Rooftop, Soil, Various Non-tarp, and Vegetation. The 2D representation of the data only gives us a partial insight into the behavior and relationships of the predictors. Since three channels are used to generate a color, plotting the data in 3D to investigate trends and behavior between classes will be more meaningful.

The 3D scatter plot shows a significant amount of overlap between the different classes. It is worth noting that it is possible to see some separation between the classes.

Prepare Data Frame for Analysis


Data Frame

df <- cbind(mutate(df, "Blue_Tarp_or_Not"=ifelse(Class != "Blue Tarp", 0, 1))) #add binary column indicating whether the Class variable is "Blue Tarp" or not
attach(df)
df$Blue_Tarp_or_Not <- factor(Blue_Tarp_or_Not, labels = c("NBT", "BT"))#, levels =c(0,1), labels = c("NBT", "BT")) #ensure new column is a factor 
"First Six Rows of Data Frame"
head(df)
df_factor  <- df[, -1]
"Last Six Rows of Data Frame"
tail(df_factor)
attach(df_factor)
#> [1] "First Six Rows of Data Frame"
#>        Class Red Green Blue Blue_Tarp_or_Not
#> 1 Vegetation  64    67   50              NBT
#> 2 Vegetation  64    67   50              NBT
#> 3 Vegetation  64    66   49              NBT
#> 4 Vegetation  75    82   53              NBT
#> 5 Vegetation  74    82   54              NBT
#> 6 Vegetation  72    76   52              NBT
#> [1] "Last Six Rows of Data Frame"
#>       Red Green Blue Blue_Tarp_or_Not
#> 63236 136   145  150               BT
#> 63237 138   146  150               BT
#> 63238 134   141  152               BT
#> 63239 136   143  151               BT
#> 63240 132   139  149               BT
#> 63241 133   141  153               BT

3D Scatter - Binary

fig1 <- plot_ly(df_factor, x=~Red, y=~Green, z=~Blue, color=~Blue_Tarp_or_Not) #Reference: https://plotly.com/r/3d-scatter-plots/ https://plotly.com/r/3d-surface-plots/
fig1 <- fig1 %>% add_markers()
fig1 <- fig1 %>% layout(scene=list(xaxis=list(title="Red"),
                     yaxis = list(title = 'Green'),
                     zaxis = list(title = 'Blue')))

fig1

After the class label is converted into a binary classifier, it is easier to see separation between the data points for blue tarps and not blue tarps.

set.seed(4)
#In order to make run times faster when tuning parameters subset data with 20%
trainIndex <- createDataPartition(df_factor$Blue_Tarp_or_Not, p=0.2,
                                  list=FALSE,
                                  times=1)
df_subset <- df_factor[trainIndex,]

Logistic Regression

Fit a Logistic Regression Model !!!Need to turn on the fold result saving …

Model

#pass
fitControl <- trainControl(method = "cv",
                           number = 10,
                           returnResamp = 'all',
                           savePredictions = 'final',
                           classProbs = TRUE) 

set.seed(4)
glm.fit <- caret::train(Blue_Tarp_or_Not~Red+Green+Blue,
                    data = df_subset, #df_factor,
                    method="glm",
                    family="binomial",
                    trControl= fitControl)

glm.fit

"Summary"
summary(glm.fit)
#> Generalized Linear Model 
#> 
#> 12649 samples
#>     3 predictor
#>     2 classes: 'NBT', 'BT' 
#> 
#> No pre-processing
#> Resampling: Cross-Validated (10 fold) 
#> Summary of sample sizes: 11384, 11385, 11384, 11383, 11383, 11384, ... 
#> Resampling results:
#> 
#>   Accuracy   Kappa    
#>   0.9956522  0.9268774
#> 
#> [1] "Summary"
#> 
#> Call:
#> NULL
#> 
#> Deviance Residuals: 
#>     Min       1Q   Median       3Q      Max  
#> -3.3875  -0.0135  -0.0005   0.0000   3.1857  
#> 
#> Coefficients:
#>             Estimate Std. Error z value Pr(>|z|)    
#> (Intercept)  1.06785    0.48917   2.183    0.029 *  
#> Red         -0.34277    0.04015  -8.538  < 2e-16 ***
#> Green       -0.22358    0.03578  -6.249 4.13e-10 ***
#> Blue         0.55714    0.04609  12.089  < 2e-16 ***
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#> 
#> (Dispersion parameter for binomial family taken to be 1)
#> 
#>     Null deviance: 3584.46  on 12648  degrees of freedom
#> Residual deviance:  317.48  on 12645  degrees of freedom
#> AIC: 325.48
#> 
#> Number of Fisher Scoring iterations: 12

ROC

Test model performance on Train data to select threshold values…

#pass
glm.prob <- predict(glm.fit, newdata=df_subset , type = "prob") #returns df with col 0 (prob not blue tarp) and 1 (prob blue tarp)
par(pty="s")
glm_roc <- roc(df_subset $Blue_Tarp_or_Not, glm.prob[,2], plot=TRUE, legacy.axes=TRUE, percent=TRUE, xlab="False Positive Percentage", ylab="True Positive Percentage", col="#965fd4", lwd=4, print.auc=TRUE, main="Log. Reg. ROC Curve") 

Thresholds

roc.info_glm <- roc(df_subset$Blue_Tarp_or_Not, glm.prob[,2], legacy.axes=TRUE)
roc.glm.df <- data.frame(tpp=roc.info_glm$sensitivities*100, fpp=(1-roc.info_glm$specificities)*100, thresholds=roc.info_glm$thresholds)
#roc.glm.df[roc.glm.df>98.5 & roc.glm.df < 99,]

glm.thresholds <- data.matrix(roc.glm.df$thresholds)

fig2 <- plot_ly(roc.glm.df, x=~tpp, y=~fpp, z=~thresholds) #Reference: https://plotly.com/r/3d-scatter-plots/ https://plotly.com/r/3d-surface-plots/
fig2 <- fig2 %>% add_markers()
fig2 <- fig2 %>% layout(scene=list(xaxis=list(title="True Positive Rate"),
                     yaxis = list(title = 'False Positive Rate'),
                     zaxis = list(title = 'Threshold')))

fig2

Confusion Matrix

lr.thresh <- 0.5
glm.pred_thresh <- factor(ifelse(glm.prob[,2]>lr.thresh,"BT", "NBT"), levels=c("NBT", "BT"))
cm.glm_thresh <- confusionMatrix(factor(glm.pred_thresh),df_subset $Blue_Tarp_or_Not, positive = "BT") 
"Threshold: 0.5"
cm.glm_thresh

acc_LR <- cm.glm_thresh[["overall"]][["Accuracy"]]*100
auc_LR <- glm_roc[["auc"]]
thresh_LR <- lr.thresh
sens_LR <-  cm.glm_thresh[["byClass"]][["Sensitivity"]]*100
spec_LR <- cm.glm_thresh[["byClass"]][["Specificity"]]*100
FDR_LR <- ((cm.glm_thresh[["table"]][2,1])/(cm.glm_thresh[["table"]][2,1]+cm.glm_thresh[["table"]][2,2]))*100
prec_LR <- cm.glm_thresh[["byClass"]][["Precision"]]*100
#> [1] "Threshold: 0.5"
#> Confusion Matrix and Statistics
#> 
#>           Reference
#> Prediction   NBT    BT
#>        NBT 12234    46
#>        BT     10   359
#>                                           
#>                Accuracy : 0.9956          
#>                  95% CI : (0.9943, 0.9967)
#>     No Information Rate : 0.968           
#>     P-Value [Acc > NIR] : < 2.2e-16       
#>                                           
#>                   Kappa : 0.9254          
#>                                           
#>  Mcnemar's Test P-Value : 2.91e-06        
#>                                           
#>             Sensitivity : 0.88642         
#>             Specificity : 0.99918         
#>          Pos Pred Value : 0.97290         
#>          Neg Pred Value : 0.99625         
#>              Prevalence : 0.03202         
#>          Detection Rate : 0.02838         
#>    Detection Prevalence : 0.02917         
#>       Balanced Accuracy : 0.94280         
#>                                           
#>        'Positive' Class : BT              
#> 

Sampling Variability

"10 Fold Results"
glm.fit$resample #point est +/- std from 10 folds "variation in the third decimal place"... 
glm.sd <- sd(glm.fit[["resample"]][["Accuracy"]]*100)
#plot(glm.fit[["resample"]][["Accuracy"]], main="Accuracy per Fold", xlab= "Fold Number", ylab="Accuracy")
#> [1] "10 Fold Results"
#>     Accuracy     Kappa parameter Resample
#> 1  0.9968379 0.9495865      none   Fold01
#> 2  0.9976266 0.9598169      none   Fold02
#> 3  0.9944664 0.9038284      none   Fold03
#> 4  0.9944708 0.9085430      none   Fold04
#> 5  0.9952607 0.9206386      none   Fold05
#> 6  0.9960474 0.9330355      none   Fold06
#> 7  0.9944664 0.9085407      none   Fold07
#> 8  0.9952532 0.9164905      none   Fold08
#> 9  0.9968354 0.9457418      none   Fold09
#> 10 0.9952569 0.9225526      none   Fold10

The average accuracy across ten folds is 99.56 with a standard deviation of 0.113.

LDA

Model

#pass
fitControl <- trainControl(method = "cv",
                           number = 10,
                           returnResamp = 'all',
                           savePredictions = 'final',
                           classProbs = TRUE)

set.seed(4)
lda.fit <- caret::train(Blue_Tarp_or_Not~Red+Green+Blue,
                    data = df_subset, #df_factor,,
                    preProcess=c("center","scale"),
                    method="lda",
                    verbose= FALSE,
                    trControl= fitControl)

lda.fit
"Summary"
summary(lda.fit)
#> Linear Discriminant Analysis 
#> 
#> 12649 samples
#>     3 predictor
#>     2 classes: 'NBT', 'BT' 
#> 
#> Pre-processing: centered (3), scaled (3) 
#> Resampling: Cross-Validated (10 fold) 
#> Summary of sample sizes: 11384, 11385, 11384, 11383, 11383, 11384, ... 
#> Resampling results:
#> 
#>   Accuracy   Kappa   
#>   0.9825284  0.737388
#> 
#> [1] "Summary"
#>             Length Class      Mode     
#> prior       2      -none-     numeric  
#> counts      2      -none-     numeric  
#> means       6      -none-     numeric  
#> scaling     3      -none-     numeric  
#> lev         2      -none-     character
#> svd         1      -none-     numeric  
#> N           1      -none-     numeric  
#> call        4      -none-     call     
#> xNames      3      -none-     character
#> problemType 1      -none-     character
#> tuneValue   1      data.frame list     
#> obsLevels   2      -none-     character
#> param       1      -none-     list

ROC

#pass
lda.prob <- predict(lda.fit, newdata=df_subset, type = "prob") #returns df with col 0 (prob not blue tarp) and 1 (prob blue tarp)
par(pty="s")
lda_roc <- roc(df_subset$Blue_Tarp_or_Not, lda.prob[,2], plot=TRUE, legacy.axes=TRUE, percent=TRUE, xlab="False Positive Percentage", ylab="True Positive Percentage", col="#965fd4", lwd=4, print.auc=TRUE, main="LDA ROC Curve") 

Thresholds

roc.info_lda <- roc(df_subset $Blue_Tarp_or_Not, lda.prob[,2], legacy.axes=TRUE)
roc.lda.df <- data.frame(tpp=roc.info_lda$sensitivities*100, fpp=(1-roc.info_lda$specificities)*100, thresholds=roc.info_lda$thresholds)
#roc.lda.df[roc.lda.df>91.5 & roc.lda.df < 91.6,]

fig3 <- plot_ly(roc.lda.df, x=~tpp, y=~fpp, z=~thresholds) #Reference: https://plotly.com/r/3d-scatter-plots/ https://plotly.com/r/3d-surface-plots/
fig3 <- fig3 %>% add_markers()
fig3 <- fig3 %>% layout(scene=list(xaxis=list(title="True Positive Rate"),
                     yaxis = list(title = 'False Positive Rate'),
                     zaxis = list(title = 'Threshold')))

fig3

Confusion Matrix

lda.thresh <- 0.5
lda.pred_thresh <- factor(ifelse(lda.prob[,2]>lda.thresh,"BT", "NBT"), levels=c("NBT", "BT"))
cm.lda_thresh <- confusionMatrix(factor(lda.pred_thresh),df_subset$Blue_Tarp_or_Not, positive = "BT") 
"Threshold: 0.5"
cm.lda_thresh

acc_lda <- cm.lda_thresh[["overall"]][["Accuracy"]]*100
auc_lda <- lda_roc[["auc"]]
thresh_lda <- lr.thresh
sens_lda <-  cm.lda_thresh[["byClass"]][["Sensitivity"]]*100
spec_lda <- cm.lda_thresh[["byClass"]][["Specificity"]]*100
FDR_lda <- ((cm.lda_thresh[["table"]][2,1])/(cm.lda_thresh[["table"]][2,1]+cm.lda_thresh[["table"]][2,2]))*100
prec_lda <- cm.lda_thresh[["byClass"]][["Precision"]]*100
#> [1] "Threshold: 0.5"
#> Confusion Matrix and Statistics
#> 
#>           Reference
#> Prediction   NBT    BT
#>        NBT 12108    81
#>        BT    136   324
#>                                          
#>                Accuracy : 0.9828         
#>                  95% CI : (0.9804, 0.985)
#>     No Information Rate : 0.968          
#>     P-Value [Acc > NIR] : < 2.2e-16      
#>                                          
#>                   Kappa : 0.7403         
#>                                          
#>  Mcnemar's Test P-Value : 0.0002466      
#>                                          
#>             Sensitivity : 0.80000        
#>             Specificity : 0.98889        
#>          Pos Pred Value : 0.70435        
#>          Neg Pred Value : 0.99335        
#>              Prevalence : 0.03202        
#>          Detection Rate : 0.02561        
#>    Detection Prevalence : 0.03637        
#>       Balanced Accuracy : 0.89445        
#>                                          
#>        'Positive' Class : BT             
#> 

Sampling Variability

"10 Fold Results"
lda.fit$resample  
lda.sd <- sd(lda.fit[["resample"]][["Accuracy"]]*100)
#> [1] "10 Fold Results"
#>     Accuracy     Kappa parameter Resample
#> 1  0.9770751 0.6831354      none   Fold01
#> 2  0.9849684 0.7835304      none   Fold02
#> 3  0.9802372 0.7089679      none   Fold03
#> 4  0.9834123 0.7384143      none   Fold04
#> 5  0.9857820 0.7731409      none   Fold05
#> 6  0.9826087 0.7519564      none   Fold06
#> 7  0.9794466 0.7005426      none   Fold07
#> 8  0.9833861 0.7321602      none   Fold08
#> 9  0.9849684 0.7576687      none   Fold09
#> 10 0.9833992 0.7443633      none   Fold10

The average accuracy across ten folds is 98.28 with a standard deviation of 0.277.

QDA

Model

#pass
fitControl <- trainControl(method = "cv",
                           number = 10,
                           returnResamp = 'all',
                           savePredictions = 'final',
                           classProbs = TRUE)

set.seed(4)
qda.fit <- caret::train(Blue_Tarp_or_Not~Red+Green+Blue,
                    data = df_subset, #df_factor,,
                    preProcess=c("center","scale"),
                    method="qda",
                    verbose= FALSE,
                    trControl= fitControl)

qda.fit
"Summary"
summary(qda.fit)
#> Quadratic Discriminant Analysis 
#> 
#> 12649 samples
#>     3 predictor
#>     2 classes: 'NBT', 'BT' 
#> 
#> Pre-processing: centered (3), scaled (3) 
#> Resampling: Cross-Validated (10 fold) 
#> Summary of sample sizes: 11384, 11385, 11384, 11383, 11383, 11384, ... 
#> Resampling results:
#> 
#>   Accuracy   Kappa    
#>   0.9946241  0.9060525
#> 
#> [1] "Summary"
#>             Length Class      Mode     
#> prior        2     -none-     numeric  
#> counts       2     -none-     numeric  
#> means        6     -none-     numeric  
#> scaling     18     -none-     numeric  
#> ldet         2     -none-     numeric  
#> lev          2     -none-     character
#> N            1     -none-     numeric  
#> call         4     -none-     call     
#> xNames       3     -none-     character
#> problemType  1     -none-     character
#> tuneValue    1     data.frame list     
#> obsLevels    2     -none-     character
#> param        1     -none-     list

ROC

#pass
qda.prob <- predict(qda.fit, newdata=df_subset , type = "prob") #returns df with col 0 (prob not blue tarp) and 1 (prob blue tarp)
par(pty="s")
qda_roc <- roc(df_subset $Blue_Tarp_or_Not, qda.prob[,2], plot=TRUE, legacy.axes=TRUE, percent=TRUE, xlab="False Positive Percentage", ylab="True Positive Percentage", col="#965fd4", lwd=4, print.auc=TRUE, main="QDA ROC Curve") 

Thresholds

roc.info_qda <- roc(df_subset$Blue_Tarp_or_Not, qda.prob[,2], legacy.axes=TRUE)
roc.qda.df <- data.frame(tpp=roc.info_qda$sensitivities*100, fpp=(1-roc.info_qda$specificities)*100, thresholds=roc.info_qda$thresholds)
#roc.qda.df[roc.qda.df>98 & roc.qda.df < 99,]

fig4 <- plot_ly(roc.qda.df, x=~tpp, y=~fpp, z=~thresholds) #Reference: https://plotly.com/r/3d-scatter-plots/ https://plotly.com/r/3d-surface-plots/
fig4 <- fig4 %>% add_markers()
fig4 <- fig4 %>% layout(scene=list(xaxis=list(title="True Positive Rate"),
                     yaxis = list(title = 'False Positive Rate'),
                     zaxis = list(title = 'Threshold')))

fig4

Confusion Matrix

qda.thresh <- 0.5
qda.pred_thresh <- factor(ifelse(qda.prob[,2]>qda.thresh,"BT", "NBT"), levels=c("NBT", "BT"))
cm.qda_thresh <- confusionMatrix(factor(qda.pred_thresh),df_subset $Blue_Tarp_or_Not, positive = "BT") 
"Threshold: 0.5"
cm.qda_thresh

acc_qda <- cm.qda_thresh[["overall"]][["Accuracy"]]*100
auc_qda <- qda_roc[["auc"]]
thresh_qda <- lr.thresh
sens_qda <-  cm.qda_thresh[["byClass"]][["Sensitivity"]]*100
spec_qda <- cm.qda_thresh[["byClass"]][["Specificity"]]*100
FDR_qda <- ((cm.qda_thresh[["table"]][2,1])/(cm.qda_thresh[["table"]][2,1]+cm.qda_thresh[["table"]][2,2]))*100
prec_qda <- cm.qda_thresh[["byClass"]][["Precision"]]*100
#> [1] "Threshold: 0.5"
#> Confusion Matrix and Statistics
#> 
#>           Reference
#> Prediction   NBT    BT
#>        NBT 12241    65
#>        BT      3   340
#>                                           
#>                Accuracy : 0.9946          
#>                  95% CI : (0.9932, 0.9958)
#>     No Information Rate : 0.968           
#>     P-Value [Acc > NIR] : < 2.2e-16       
#>                                           
#>                   Kappa : 0.9063          
#>                                           
#>  Mcnemar's Test P-Value : 1.389e-13       
#>                                           
#>             Sensitivity : 0.83951         
#>             Specificity : 0.99975         
#>          Pos Pred Value : 0.99125         
#>          Neg Pred Value : 0.99472         
#>              Prevalence : 0.03202         
#>          Detection Rate : 0.02688         
#>    Detection Prevalence : 0.02712         
#>       Balanced Accuracy : 0.91963         
#>                                           
#>        'Positive' Class : BT              
#> 

Sampling Variability

"10 Fold Results"
qda.fit$resample #point est +/- std from 10 folds "variation in the third decimal place"... 
qda.sd <- sd(qda.fit[["resample"]][["Accuracy"]]*100)
#> [1] "10 Fold Results"
#>     Accuracy     Kappa parameter Resample
#> 1  0.9968379 0.9470877      none   Fold01
#> 2  0.9960443 0.9313043      none   Fold02
#> 3  0.9936759 0.8886566      none   Fold03
#> 4  0.9944708 0.9038432      none   Fold04
#> 5  0.9944708 0.9038432      none   Fold05
#> 6  0.9952569 0.9186234      none   Fold06
#> 7  0.9944664 0.9038409      none   Fold07
#> 8  0.9944620 0.9012853      none   Fold08
#> 9  0.9936709 0.8856729      none   Fold09
#> 10 0.9928854 0.8763669      none   Fold10

The average accuracy across ten folds is 99.46 with a standard deviation of 0.117.

KNN

Model

#pass
fitControl <- trainControl(method = "cv",
                           number = 10,
                           returnResamp = 'all',
                           savePredictions = 'final',
                           classProbs = TRUE)

set.seed(4)
knn.fit <- train(Blue_Tarp_or_Not~Red+Green+Blue,
                    data = df_subset, #df_factor,,
                    preProcess=c("center","scale"),
                    method="knn",
                    trControl= fitControl,
                    tuneLength=10
                    )

knn.fit
#> k-Nearest Neighbors 
#> 
#> 12649 samples
#>     3 predictor
#>     2 classes: 'NBT', 'BT' 
#> 
#> Pre-processing: centered (3), scaled (3) 
#> Resampling: Cross-Validated (10 fold) 
#> Summary of sample sizes: 11384, 11385, 11384, 11383, 11383, 11384, ... 
#> Resampling results across tuning parameters:
#> 
#>   k   Accuracy   Kappa    
#>    5  0.9974702  0.9597379
#>    7  0.9970750  0.9531862
#>    9  0.9966004  0.9448613
#>   11  0.9962843  0.9398857
#>   13  0.9957310  0.9302483
#>   15  0.9958104  0.9316068
#>   17  0.9956522  0.9287919
#>   19  0.9955731  0.9271888
#>   21  0.9956521  0.9282576
#>   23  0.9954941  0.9251812
#> 
#> Accuracy was used to select the optimal model using the largest value.
#> The final value used for the model was k = 5.
plot(knn.fit)

ROC

#pass
knn.prob <- predict(knn.fit, newdata=df_subset , type = "prob") #returns df with col 0 (prob not blue tarp) and 1 (prob blue tarp)
par(pty="s")
knn_roc <- roc(df_subset $Blue_Tarp_or_Not, knn.prob[,2], plot=TRUE, legacy.axes=TRUE, percent=TRUE, xlab="False Positive Percentage", ylab="True Positive Percentage", col="#965fd4", lwd=4, print.auc=TRUE, main="KNN ROC Curve") 

Thresholds

Not sure why there are only 10 values for this one…?

roc.info_knn <- roc(df_subset$Blue_Tarp_or_Not, knn.prob[,2], legacy.axes=TRUE)
roc.knn.df <- data.frame(tpp=roc.info_knn$sensitivities*100, fpp=(1-roc.info_knn$specificities)*100, thresholds=roc.info_knn$thresholds)
#roc.knn.df[roc.knn.df>99 & roc.knn.df < 100,]
#roc.knn.df

fig5 <- plot_ly(roc.knn.df, x=~tpp, y=~fpp, z=~thresholds) #Reference: https://plotly.com/r/3d-scatter-plots/ https://plotly.com/r/3d-surface-plots/
fig5 <- fig5 %>% add_markers()
fig5 <- fig5 %>% layout(scene=list(xaxis=list(title="True Positive Rate"),
                     yaxis = list(title = 'False Positive Rate'),
                     zaxis = list(title = 'Threshold')))

fig5

Confusion Matrix

knn.thresh <- 0.5
knn.pred_thresh <- factor(ifelse(knn.prob[,2]>knn.thresh,"BT", "NBT"), levels=c("NBT", "BT"))
cm.knn_thresh <- confusionMatrix(factor(knn.pred_thresh),df_subset $Blue_Tarp_or_Not, positive = "BT") 
"Threshold: 0.5"
cm.knn_thresh

acc_knn <- cm.knn_thresh[["overall"]][["Accuracy"]]*100
auc_knn <- knn_roc[["auc"]]
thresh_knn <- lr.thresh
sens_knn <-  cm.knn_thresh[["byClass"]][["Sensitivity"]]*100
spec_knn <- cm.knn_thresh[["byClass"]][["Specificity"]]*100
FDR_knn <- ((cm.knn_thresh[["table"]][2,1])/(cm.knn_thresh[["table"]][2,1]+cm.knn_thresh[["table"]][2,2]))*100
prec_knn <- cm.knn_thresh[["byClass"]][["Precision"]]*100
k_knn <- knn.fit[["bestTune"]][["k"]]
#> [1] "Threshold: 0.5"
#> Confusion Matrix and Statistics
#> 
#>           Reference
#> Prediction   NBT    BT
#>        NBT 12228     8
#>        BT     16   397
#>                                           
#>                Accuracy : 0.9981          
#>                  95% CI : (0.9972, 0.9988)
#>     No Information Rate : 0.968           
#>     P-Value [Acc > NIR] : <2e-16          
#>                                           
#>                   Kappa : 0.9697          
#>                                           
#>  Mcnemar's Test P-Value : 0.153           
#>                                           
#>             Sensitivity : 0.98025         
#>             Specificity : 0.99869         
#>          Pos Pred Value : 0.96126         
#>          Neg Pred Value : 0.99935         
#>              Prevalence : 0.03202         
#>          Detection Rate : 0.03139         
#>    Detection Prevalence : 0.03265         
#>       Balanced Accuracy : 0.98947         
#>                                           
#>        'Positive' Class : BT              
#> 

Sampling Variability

"10 Fold Results"
knn.fit$resample #point est +/- std from 10 folds "variation in the third decimal place"... 
knn.sd <- sd(knn.fit[["resample"]][["Accuracy"]]*100)
#> [1] "10 Fold Results"
#>      Accuracy     Kappa  k Resample
#> 1   0.9976285 0.9626311  5   Fold01
#> 2   0.9968379 0.9495865  7   Fold01
#> 3   0.9968379 0.9495865  9   Fold01
#> 4   0.9960474 0.9377185 11   Fold01
#> 5   0.9960474 0.9377185 13   Fold01
#> 6   0.9960474 0.9377185 15   Fold01
#> 7   0.9960474 0.9377185 17   Fold01
#> 8   0.9968379 0.9495865 19   Fold01
#> 9   0.9968379 0.9495865 21   Fold01
#> 10  0.9960474 0.9362303 23   Fold01
#> 11  0.9984177 0.9741830  5   Fold02
#> 12  0.9984177 0.9741830  7   Fold02
#> 13  0.9976266 0.9608005  9   Fold02
#> 14  0.9976266 0.9608005 11   Fold02
#> 15  0.9976266 0.9608005 13   Fold02
#> 16  0.9976266 0.9608005 15   Fold02
#> 17  0.9968354 0.9483660 17   Fold02
#> 18  0.9968354 0.9483660 19   Fold02
#> 19  0.9976266 0.9608005 21   Fold02
#> 20  0.9976266 0.9608005 23   Fold02
#> 21  0.9968379 0.9495865  5   Fold03
#> 22  0.9968379 0.9483673  7   Fold03
#> 23  0.9976285 0.9608015  9   Fold03
#> 24  0.9976285 0.9608015 11   Fold03
#> 25  0.9968379 0.9470877 13   Fold03
#> 26  0.9968379 0.9470877 15   Fold03
#> 27  0.9968379 0.9470877 17   Fold03
#> 28  0.9968379 0.9470877 19   Fold03
#> 29  0.9968379 0.9470877 21   Fold03
#> 30  0.9968379 0.9470877 23   Fold03
#> 31  0.9976303 0.9634815  5   Fold04
#> 32  0.9968404 0.9507479  7   Fold04
#> 33  0.9960506 0.9377177  9   Fold04
#> 34  0.9936809 0.9014958 11   Fold04
#> 35  0.9936809 0.8991737 13   Fold04
#> 36  0.9936809 0.8991737 15   Fold04
#> 37  0.9936809 0.8991737 17   Fold04
#> 38  0.9936809 0.9014958 19   Fold04
#> 39  0.9944708 0.9128048 21   Fold04
#> 40  0.9944708 0.9107247 23   Fold04
#> 41  0.9976303 0.9626306  5   Fold05
#> 42  0.9968404 0.9495869  7   Fold05
#> 43  0.9968404 0.9495869  9   Fold05
#> 44  0.9976303 0.9626306 11   Fold05
#> 45  0.9968404 0.9495869 13   Fold05
#> 46  0.9952607 0.9225546 15   Fold05
#> 47  0.9952607 0.9225546 17   Fold05
#> 48  0.9952607 0.9225546 19   Fold05
#> 49  0.9952607 0.9225546 21   Fold05
#> 50  0.9952607 0.9225546 23   Fold05
#> 51  0.9984190 0.9741842  5   Fold06
#> 52  0.9976285 0.9608031  7   Fold06
#> 53  0.9976285 0.9608031  9   Fold06
#> 54  0.9976285 0.9608031 11   Fold06
#> 55  0.9976285 0.9608031 13   Fold06
#> 56  0.9976285 0.9608031 15   Fold06
#> 57  0.9976285 0.9608031 17   Fold06
#> 58  0.9968379 0.9470911 19   Fold06
#> 59  0.9968379 0.9470911 21   Fold06
#> 60  0.9960474 0.9330355 23   Fold06
#> 61  0.9960474 0.9404891  5   Fold07
#> 62  0.9960474 0.9404891  7   Fold07
#> 63  0.9960474 0.9404891  9   Fold07
#> 64  0.9960474 0.9391341 11   Fold07
#> 65  0.9952569 0.9261199 13   Fold07
#> 66  0.9944664 0.9128024 15   Fold07
#> 67  0.9936759 0.8991711 17   Fold07
#> 68  0.9936759 0.8967368 19   Fold07
#> 69  0.9928854 0.8824094 21   Fold07
#> 70  0.9928854 0.8824094 23   Fold07
#> 71  0.9992089 0.9869335  5   Fold08
#> 72  0.9976266 0.9608005  7   Fold08
#> 73  0.9952532 0.9186126  9   Fold08
#> 74  0.9952532 0.9186126 11   Fold08
#> 75  0.9944620 0.9038261 13   Fold08
#> 76  0.9960443 0.9313043 15   Fold08
#> 77  0.9952532 0.9164905 17   Fold08
#> 78  0.9952532 0.9164905 19   Fold08
#> 79  0.9952532 0.9164905 21   Fold08
#> 80  0.9952532 0.9164905 23   Fold08
#> 81  0.9952532 0.9206296  5   Fold09
#> 82  0.9960443 0.9346675  7   Fold09
#> 83  0.9952532 0.9206296  9   Fold09
#> 84  0.9952532 0.9206296 11   Fold09
#> 85  0.9952532 0.9206296 13   Fold09
#> 86  0.9968354 0.9470864 15   Fold09
#> 87  0.9976266 0.9598169 17   Fold09
#> 88  0.9968354 0.9457418 19   Fold09
#> 89  0.9960443 0.9330281 21   Fold09
#> 90  0.9968354 0.9457418 23   Fold09
#> 91  0.9976285 0.9626296  5   Fold10
#> 92  0.9976285 0.9626296  7   Fold10
#> 93  0.9968379 0.9495855  9   Fold10
#> 94  0.9960474 0.9362303 11   Fold10
#> 95  0.9936759 0.8967368 13   Fold10
#> 96  0.9936759 0.8967368 15   Fold10
#> 97  0.9936759 0.8967368 17   Fold10
#> 98  0.9936759 0.8967368 19   Fold10
#> 99  0.9944664 0.9107224 21   Fold10
#> 100 0.9936759 0.8967368 23   Fold10

The average accuracy across ten folds when k = 5 is 99.81 with a standard deviation of 0.144.

Random Forest

Model

#pass
fitControl <- trainControl(method = "cv",
                           number = 10,
                           returnResamp = 'all',
                           savePredictions = 'final',
                           classProbs = TRUE)

set.seed(4)
rf.fit <- train(Blue_Tarp_or_Not~Red+Green+Blue,
                    data = df_subset, #df_factor,,
                    preProcess=c("center","scale"),
                    method="rf", #what is the difference between the different caret rf models??
                    trControl= fitControl,
                    tuneLength=3
                    )

rf.fit
#> note: only 2 unique complexity parameters in default grid. Truncating the grid to 2 .
#> 
#> Random Forest 
#> 
#> 12649 samples
#>     3 predictor
#>     2 classes: 'NBT', 'BT' 
#> 
#> Pre-processing: centered (3), scaled (3) 
#> Resampling: Cross-Validated (10 fold) 
#> Summary of sample sizes: 11384, 11385, 11384, 11383, 11383, 11384, ... 
#> Resampling results across tuning parameters:
#> 
#>   mtry  Accuracy   Kappa    
#>   2     0.9968378  0.9488261
#>   3     0.9967588  0.9480005
#> 
#> Accuracy was used to select the optimal model using the largest value.
#> The final value used for the model was mtry = 2.
plot(rf.fit)

ROC

#pass
RF.prob <- predict(rf.fit, newdata=df_subset , type = "prob") #returns df with col 0 (prob not blue tarp) and 1 (prob blue tarp)
par(pty="s")
RF_roc <- roc(df_subset $Blue_Tarp_or_Not, RF.prob[,2], plot=TRUE, legacy.axes=TRUE, percent=TRUE, xlab="False Positive Percentage", ylab="True Positive Percentage", col="#965fd4", lwd=4, print.auc=TRUE, main="RF ROC Curve") 

Thresholds

roc.info_rf <- roc(df_subset$Blue_Tarp_or_Not, RF.prob[,2], legacy.axes=TRUE)
roc.rf.df <- data.frame(tpp=roc.info_rf$sensitivities*100, fpp=(1-roc.info_rf$specificities)*100, thresholds=roc.info_rf$thresholds)
#roc.rf.df[roc.rf.df>99 & roc.rf.df < 100,]
#roc.rf.df

fig6 <- plot_ly(roc.rf.df, x=~tpp, y=~fpp, z=~thresholds) #Reference: https://plotly.com/r/3d-scatter-plots/ https://plotly.com/r/3d-surface-plots/
fig6 <- fig6 %>% add_markers()
fig6 <- fig6 %>% layout(scene=list(xaxis=list(title="True Positive Rate"),
                     yaxis = list(title = 'False Positive Rate'),
                     zaxis = list(title = 'Threshold')))

fig6

Confusion Matrix

RF.thresh <- 0.5
RF.pred_thresh <- factor(ifelse(RF.prob[,2]>RF.thresh,"BT", "NBT"), levels=c("NBT", "BT"))
cm.RF_thresh <- confusionMatrix(factor(RF.pred_thresh),df_subset $Blue_Tarp_or_Not, positive = "BT") 
"Threshold: 0.5"
cm.RF_thresh

acc_RF <- cm.RF_thresh[["overall"]][["Accuracy"]]*100
auc_RF <- RF_roc[["auc"]]
thresh_RF <- lr.thresh
sens_RF <-  cm.RF_thresh[["byClass"]][["Sensitivity"]]*100
spec_RF <- cm.RF_thresh[["byClass"]][["Specificity"]]*100
FDR_RF <- ((cm.RF_thresh[["table"]][2,1])/(cm.RF_thresh[["table"]][2,1]+cm.RF_thresh[["table"]][2,2]))*100
prec_RF <- cm.RF_thresh[["byClass"]][["Precision"]]*100
mtry_best <- rf.fit[["bestTune"]][["mtry"]]
#> [1] "Threshold: 0.5"
#> Confusion Matrix and Statistics
#> 
#>           Reference
#> Prediction   NBT    BT
#>        NBT 12244     5
#>        BT      0   400
#>                                           
#>                Accuracy : 0.9996          
#>                  95% CI : (0.9991, 0.9999)
#>     No Information Rate : 0.968           
#>     P-Value [Acc > NIR] : < 2e-16         
#>                                           
#>                   Kappa : 0.9936          
#>                                           
#>  Mcnemar's Test P-Value : 0.07364         
#>                                           
#>             Sensitivity : 0.98765         
#>             Specificity : 1.00000         
#>          Pos Pred Value : 1.00000         
#>          Neg Pred Value : 0.99959         
#>              Prevalence : 0.03202         
#>          Detection Rate : 0.03162         
#>    Detection Prevalence : 0.03162         
#>       Balanced Accuracy : 0.99383         
#>                                           
#>        'Positive' Class : BT              
#> 

Sampling Variability

"10 Fold Results"
rf.fit$resample #point est +/- std from 10 folds "variation in the third decimal place"... 
rf.sd <- sd(rf.fit[["resample"]][["Accuracy"]]*100)
#> [1] "10 Fold Results"
#>     Accuracy     Kappa mtry Resample
#> 1  0.9976285 0.9617382    2   Fold01
#> 2  0.9960474 0.9377185    3   Fold01
#> 3  0.9992089 0.9869335    2   Fold02
#> 4  0.9992089 0.9869335    3   Fold02
#> 5  0.9960474 0.9346692    2   Fold03
#> 6  0.9968379 0.9483673    3   Fold03
#> 7  0.9976303 0.9634815    2   Fold04
#> 8  0.9976303 0.9634815    3   Fold04
#> 9  0.9960506 0.9346736    2   Fold05
#> 10 0.9952607 0.9206386    3   Fold05
#> 11 0.9984190 0.9741842    2   Fold06
#> 12 0.9984190 0.9741842    3   Fold06
#> 13 0.9960474 0.9404891    2   Fold07
#> 14 0.9960474 0.9404891    3   Fold07
#> 15 0.9960443 0.9313043    2   Fold08
#> 16 0.9968354 0.9457418    3   Fold08
#> 17 0.9960443 0.9346675    2   Fold09
#> 18 0.9960443 0.9346675    3   Fold09
#> 19 0.9952569 0.9261199    2   Fold10
#> 20 0.9952569 0.9277831    3   Fold10

The average accuracy across ten folds when mtry = 2 is 99.96 with a standard deviation of 0.127.

SVM

Model

#pass
fitControl <- trainControl(method = "cv",
                           number = 10,
                           returnResamp = 'all',
                           savePredictions = 'final',
                           classProbs = TRUE)

set.seed(4)
svm.radial.fit <- train(Blue_Tarp_or_Not~Red+Green+Blue,
                    data = df_subset, #df_factor,,
                    preProcess=c("center","scale"),
                    method="svmRadial",
                    trControl= fitControl,
                    tuneLength=10
                    #tuneGrid = expand.grid(C=seq(0,10, length=10),
                    #                           sigma =seq(0,10, length=10))
                    )

svm.radial.fit
"Summary"
summary(svm.radial.fit)
#> Support Vector Machines with Radial Basis Function Kernel 
#> 
#> 12649 samples
#>     3 predictor
#>     2 classes: 'NBT', 'BT' 
#> 
#> Pre-processing: centered (3), scaled (3) 
#> Resampling: Cross-Validated (10 fold) 
#> Summary of sample sizes: 11384, 11385, 11384, 11383, 11383, 11384, ... 
#> Resampling results across tuning parameters:
#> 
#>   C       Accuracy   Kappa    
#>     0.25  0.9959682  0.9337974
#>     0.50  0.9962054  0.9377061
#>     1.00  0.9963636  0.9404512
#>     2.00  0.9970750  0.9522407
#>     4.00  0.9969959  0.9509235
#>     8.00  0.9969958  0.9507358
#>    16.00  0.9971538  0.9532823
#>    32.00  0.9969955  0.9503985
#>    64.00  0.9969957  0.9508143
#>   128.00  0.9968375  0.9480134
#> 
#> Tuning parameter 'sigma' was held constant at a value of 9.406735
#> Accuracy was used to select the optimal model using the largest value.
#> The final values used for the model were sigma = 9.406735 and C = 16.
#> [1] "Summary"
#> Length  Class   Mode 
#>      1   ksvm     S4
plot(svm.radial.fit)

Both linear and poly SVM functions were considered. Radial SVM produced the highest accuracy values of the three methods. SVM radial was chosen for building the SVM model.

ROC

#pass
SVM.prob <- predict(svm.radial.fit, newdata=df_subset , type = "prob") #returns df with col 0 (prob not blue tarp) and 1 (prob blue tarp)
par(pty="s")
SVM_roc <- roc(df_subset $Blue_Tarp_or_Not, SVM.prob[,2], plot=TRUE, legacy.axes=TRUE, percent=TRUE, xlab="False Positive Percentage", ylab="True Positive Percentage", col="#965fd4", lwd=4, print.auc=TRUE, main="SVM ROC Curve") 

Thresholds

roc.info_svm <- roc(df_subset$Blue_Tarp_or_Not, SVM.prob[,2], legacy.axes=TRUE)
roc.svm.df <- data.frame(tpp=roc.info_svm$sensitivities*100, fpp=(1-roc.info_svm$specificities)*100, thresholds=roc.info_svm$thresholds)
#roc.svm.df[roc.svm.df>99 & roc.svm.df < 100,]
#roc.svm.df

fig7 <- plot_ly(roc.svm.df, x=~tpp, y=~fpp, z=~thresholds) #Reference: https://plotly.com/r/3d-scatter-plots/ https://plotly.com/r/3d-surface-plots/
fig7 <- fig7 %>% add_markers()
fig7 <- fig7 %>% layout(scene=list(xaxis=list(title="True Positive Rate"),
                     yaxis = list(title = 'False Positive Rate'),
                     zaxis = list(title = 'Threshold')))

fig7

Confusion Matrix

SVM.thresh <- 0.5
SVM.pred_thresh <- factor(ifelse(SVM.prob[,2]>SVM.thresh,"BT", "NBT"), levels=c("NBT", "BT"))
cm.SVM_thresh <- confusionMatrix(factor(SVM.pred_thresh),df_subset $Blue_Tarp_or_Not, positive = "BT") 
"Threshold: 0.5"
cm.SVM_thresh

acc_SVM <- cm.SVM_thresh[["overall"]][["Accuracy"]]*100
auc_SVM <- SVM_roc[["auc"]]
thresh_SVM <- lr.thresh
sens_SVM <-  cm.SVM_thresh[["byClass"]][["Sensitivity"]]*100
spec_SVM <- cm.SVM_thresh[["byClass"]][["Specificity"]]*100
FDR_SVM <- ((cm.SVM_thresh[["table"]][2,1])/(cm.SVM_thresh[["table"]][2,1]+cm.SVM_thresh[["table"]][2,2]))*100
prec_SVM <- cm.SVM_thresh[["byClass"]][["Precision"]]*100
#sigma_best <-   fill this in after best svm model chosen 
#C_best <- 
#> [1] "Threshold: 0.5"
#> Confusion Matrix and Statistics
#> 
#>           Reference
#> Prediction   NBT    BT
#>        NBT 12234    17
#>        BT     10   388
#>                                           
#>                Accuracy : 0.9979          
#>                  95% CI : (0.9969, 0.9986)
#>     No Information Rate : 0.968           
#>     P-Value [Acc > NIR] : <2e-16          
#>                                           
#>                   Kappa : 0.9653          
#>                                           
#>  Mcnemar's Test P-Value : 0.2482          
#>                                           
#>             Sensitivity : 0.95802         
#>             Specificity : 0.99918         
#>          Pos Pred Value : 0.97487         
#>          Neg Pred Value : 0.99861         
#>              Prevalence : 0.03202         
#>          Detection Rate : 0.03067         
#>    Detection Prevalence : 0.03146         
#>       Balanced Accuracy : 0.97860         
#>                                           
#>        'Positive' Class : BT              
#> 

Sampling Variability

"10 Fold Results"
svm.radial.fit$resample #point est +/- std from 10 folds "variation in the third decimal place"... 
svm.sd <- sd(svm.radial.fit[["resample"]][["Accuracy"]]*100)
#> [1] "10 Fold Results"
#>      Accuracy     Kappa    sigma      C Resample
#> 1   0.9968379 0.9495865 9.406735   0.25   Fold01
#> 2   0.9976285 0.9617382 9.406735   0.50   Fold01
#> 3   0.9976285 0.9617382 9.406735   1.00   Fold01
#> 4   0.9984190 0.9747933 9.406735   2.00   Fold01
#> 5   0.9984190 0.9747933 9.406735   4.00   Fold01
#> 6   0.9984190 0.9747933 9.406735   8.00   Fold01
#> 7   0.9984190 0.9747933 9.406735  16.00   Fold01
#> 8   0.9984190 0.9747933 9.406735  32.00   Fold01
#> 9   0.9984190 0.9747933 9.406735  64.00   Fold01
#> 10  0.9992095 0.9872461 9.406735 128.00   Fold01
#> 11  0.9968354 0.9470864 9.406735   0.25   Fold02
#> 12  0.9976266 0.9608005 9.406735   0.50   Fold02
#> 13  0.9984177 0.9741830 9.406735   1.00   Fold02
#> 14  0.9984177 0.9741830 9.406735   2.00   Fold02
#> 15  0.9984177 0.9741830 9.406735   4.00   Fold02
#> 16  0.9984177 0.9741830 9.406735   8.00   Fold02
#> 17  0.9984177 0.9741830 9.406735  16.00   Fold02
#> 18  0.9984177 0.9741830 9.406735  32.00   Fold02
#> 19  0.9984177 0.9741830 9.406735  64.00   Fold02
#> 20  0.9984177 0.9741830 9.406735 128.00   Fold02
#> 21  0.9976285 0.9608015 9.406735   0.25   Fold03
#> 22  0.9976285 0.9608015 9.406735   0.50   Fold03
#> 23  0.9960474 0.9346692 9.406735   1.00   Fold03
#> 24  0.9960474 0.9330298 9.406735   2.00   Fold03
#> 25  0.9952569 0.9225510 9.406735   4.00   Fold03
#> 26  0.9944664 0.9085369 9.406735   8.00   Fold03
#> 27  0.9944664 0.9085369 9.406735  16.00   Fold03
#> 28  0.9944664 0.9085369 9.406735  32.00   Fold03
#> 29  0.9944664 0.9085369 9.406735  64.00   Fold03
#> 30  0.9936759 0.8941755 9.406735 128.00   Fold03
#> 31  0.9936809 0.8967395 9.406735   0.25   Fold04
#> 32  0.9944708 0.9107247 9.406735   0.50   Fold04
#> 33  0.9944708 0.9107247 9.406735   1.00   Fold04
#> 34  0.9960506 0.9377177 9.406735   2.00   Fold04
#> 35  0.9960506 0.9377177 9.406735   4.00   Fold04
#> 36  0.9960506 0.9377177 9.406735   8.00   Fold04
#> 37  0.9968404 0.9507479 9.406735  16.00   Fold04
#> 38  0.9976303 0.9634815 9.406735  32.00   Fold04
#> 39  0.9968404 0.9507479 9.406735  64.00   Fold04
#> 40  0.9968404 0.9507479 9.406735 128.00   Fold04
#> 41  0.9968404 0.9495869 9.406735   0.25   Fold05
#> 42  0.9952607 0.9225546 9.406735   0.50   Fold05
#> 43  0.9952607 0.9225546 9.406735   1.00   Fold05
#> 44  0.9960506 0.9362319 9.406735   2.00   Fold05
#> 45  0.9960506 0.9362319 9.406735   4.00   Fold05
#> 46  0.9968404 0.9483697 9.406735   8.00   Fold05
#> 47  0.9976303 0.9608041 9.406735  16.00   Fold05
#> 48  0.9976303 0.9608041 9.406735  32.00   Fold05
#> 49  0.9976303 0.9608041 9.406735  64.00   Fold05
#> 50  0.9976303 0.9608041 9.406735 128.00   Fold05
#> 51  0.9968379 0.9470911 9.406735   0.25   Fold06
#> 52  0.9976285 0.9608031 9.406735   0.50   Fold06
#> 53  0.9976285 0.9608031 9.406735   1.00   Fold06
#> 54  0.9984190 0.9741842 9.406735   2.00   Fold06
#> 55  0.9984190 0.9741842 9.406735   4.00   Fold06
#> 56  0.9984190 0.9741842 9.406735   8.00   Fold06
#> 57  0.9984190 0.9741842 9.406735  16.00   Fold06
#> 58  0.9976285 0.9608031 9.406735  32.00   Fold06
#> 59  0.9984190 0.9741842 9.406735  64.00   Fold06
#> 60  0.9984190 0.9741842 9.406735 128.00   Fold06
#> 61  0.9944664 0.9107224 9.406735   0.25   Fold07
#> 62  0.9952569 0.9243783 9.406735   0.50   Fold07
#> 63  0.9952569 0.9261199 9.406735   1.00   Fold07
#> 64  0.9968379 0.9507466 9.406735   2.00   Fold07
#> 65  0.9976285 0.9634805 9.406735   4.00   Fold07
#> 66  0.9976285 0.9634805 9.406735   8.00   Fold07
#> 67  0.9976285 0.9634805 9.406735  16.00   Fold07
#> 68  0.9976285 0.9634805 9.406735  32.00   Fold07
#> 69  0.9968379 0.9518554 9.406735  64.00   Fold07
#> 70  0.9968379 0.9518554 9.406735 128.00   Fold07
#> 71  0.9968354 0.9457418 9.406735   0.25   Fold08
#> 72  0.9960443 0.9313043 9.406735   0.50   Fold08
#> 73  0.9968354 0.9457418 9.406735   1.00   Fold08
#> 74  0.9984177 0.9735432 9.406735   2.00   Fold08
#> 75  0.9976266 0.9598169 9.406735   4.00   Fold08
#> 76  0.9976266 0.9598169 9.406735   8.00   Fold08
#> 77  0.9976266 0.9598169 9.406735  16.00   Fold08
#> 78  0.9976266 0.9598169 9.406735  32.00   Fold08
#> 79  0.9976266 0.9598169 9.406735  64.00   Fold08
#> 80  0.9968354 0.9470864 9.406735 128.00   Fold08
#> 81  0.9944620 0.9062394 9.406735   0.25   Fold09
#> 82  0.9944620 0.9062394 9.406735   0.50   Fold09
#> 83  0.9944620 0.9062394 9.406735   1.00   Fold09
#> 84  0.9944620 0.9062394 9.406735   2.00   Fold09
#> 85  0.9936709 0.8914835 9.406735   4.00   Fold09
#> 86  0.9936709 0.8914835 9.406735   8.00   Fold09
#> 87  0.9936709 0.8914835 9.406735  16.00   Fold09
#> 88  0.9928797 0.8763478 9.406735  32.00   Fold09
#> 89  0.9936709 0.8914835 9.406735  64.00   Fold09
#> 90  0.9936709 0.8914835 9.406735 128.00   Fold09
#> 91  0.9952569 0.9243783 9.406735   0.25   Fold10
#> 92  0.9960474 0.9377160 9.406735   0.50   Fold10
#> 93  0.9976285 0.9617382 9.406735   1.00   Fold10
#> 94  0.9976285 0.9617382 9.406735   2.00   Fold10
#> 95  0.9984190 0.9747928 9.406735   4.00   Fold10
#> 96  0.9984190 0.9747928 9.406735   8.00   Fold10
#> 97  0.9984190 0.9747928 9.406735  16.00   Fold10
#> 98  0.9976285 0.9617382 9.406735  32.00   Fold10
#> 99  0.9976285 0.9617382 9.406735  64.00   Fold10
#> 100 0.9968379 0.9483684 9.406735 128.00   Fold10

The average accuracy across ten folds is 99.79 with a standard deviation of 0.159.

K-Folds Out of Sampling Performance

Table 2 - Performance Metrics: 10-Fold Cross-Validation Metrics

Method KNN (k = 5) LDA QDA Log. Regression Random Forest (tuning param = ?) SVM (tuning param = ?)
Accuracy 99.81% 98.28% 99.46% 99.56% 99.96 99.79
AUC 99.99% 98.93% 99.82% 99.91% 99.37 99.97
ROC
Threshold 0.5 0.5 0.5 0.5 0.5 0.5
Sensitivity 98.02% 80% 83.95% 88.64% 98.77 95.8
Specificity 99.87% 98.89% 99.98% 99.92% 100 99.92
FDR 3.87% 29.57% 0.87% 2.71% 0 2.51
Precision 96.13% 70.43% 99.13% 97.29% 100 97.49

Model Performance

Discussion

(discussion on FHO data why we do this… what the benefits are… potential pitfalls)

(discussion somewhere about ROC curves AUC and… other metrics)

handling imbalanced classes

Hold-Out Test Sample Performance

Table 3 - Performance Metrics: Hold-Out Test Data Set Scores

#|                   Method | KNN (k = `r k_knn`) |    LDA    |    QDA    | Log. Regression | Random Forest (tuning param = ?) | SVM (tuning param = ?)|
#|-------------------------:|:--------------:|:---------:|:---------:|:---------------:|:--------------------------------:|:---------------------:|
#|                 Accuracy | `r acc_knn_FHO`%   | `r acc_lda_FHO`%   | `r acc_qda_FHO`%   | `r acc_LR_FHO`%   | `r acc_RF_FHO`    | `r acc_SVM_FHO`   |
#|                      AUC | `r auc_knn_FHO`%   | `r auc_lda_FHO`%   | `r auc_qda_FHO`%   | `r auc_LR_FHO`%   | `r auc_RF_FHO`    | `r auc_SVM_FHO`   |
#|                      ROC |                    |                    |                    |                   |                   |                   |
#|                Threshold | `r thresh_knn_FHO` | `r thresh_lda_FHO` | `r thresh_qda_FHO` | `r thresh_LR_FHO` | `r thresh_RF_FHO` |`r thresh_SVM_FHO` |
#| Sensitivity=Recall=Power | `r sens_knn_FHO`%  | `r sens_lda_FHO`%  | `r sens_qda_FHO`%  | `r sens_LR_FHO`%  |`r sens_RF_FHO`    | `r sens_SVM_FHO`  |
#|        Specificity=1-FPR | `r spec_knn_FHO`%  | `r spec_lda_FHO`%  | `r spec_qda_FHO`%  | `r spec_LR_FHO`%  |`r spec_RF_FHO`    |`r spec_SVM_FHO`   |
#|                      FDR | `r FDR_knn_FHO`%   | `r FDR_lda_FHO`%   | `r FDR_qda_FHO`%   | `r FDR_LR_FHO`%   | `r FDR_RF_FHO`    |`r FDR_SVM_FHO`    |
#|            Precision=PPV | `r prec_knn_FHO`%  | `r prec_lda_FHO`%  | `r prec_qda_FHO`%  | `r prec_LR_FHO`%  |`r prec_RF_FHO`    | `r prec_SVM_FHO`  |

Future Work

#consider if I was able to find an additional data source like lidar or infrared to pair with this dataset to improve model performance... ? 

References and Works Cited

Appendix A: Analysis Methods Reference Info

LDA QDA
Assumptions this is a lot of text what happens when you put this much text in this table
Tuning Parameters